package com.tmsps.ne4spring2.util;

import java.lang.reflect.Field;
import java.math.BigDecimal;
import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.persistence.Id;
import javax.persistence.Transient;

import com.tmsps.ne4spring2.model.DbModel;

public class ClassTools {
	/**
	 * 设置BEAN属性值
	 * 
	 * @param field
	 * @param obj
	 * @param val
	 */
	public static void setClassVal(Field field, Object obj, Object val) {
		boolean acc = field.isAccessible();
		field.setAccessible(true);
		try {
			field.set(obj, val);
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			field.setAccessible(acc);
		}
	}

	/**
	 * 获取属性值
	 * 
	 * @param field
	 * @param obj
	 * @return
	 */
	public static Object getClassVal(Field field, Object obj) {
		boolean acc = field.isAccessible();
		try {
			field.setAccessible(true);
			return field.get(obj);
		} catch (Exception e) {
			e.printStackTrace();
			return null;
		} finally {
			field.setAccessible(acc);
		}

	}

	/**
	 * 获取Class的属性名称
	 * 
	 * @param clazz
	 * @return
	 */
	public static List<String> getClassProperties(Class<?> clazz) {
		List<String> list = new ArrayList<String>();
		List<Field> fields = getClassFields(clazz);
		for (Field field : fields) {
			if (field.isAnnotationPresent(Transient.class)) {
				continue;
			}
			list.add(field.getName());
		}

		return list;
	}

	public static List<Field> getClassFields(Class<?> clazz) {
		List<Field> clazzField = new ArrayList<Field>();
		Field[] fields = clazz.getDeclaredFields();
		for (Field field : fields) {
			if (field.isAnnotationPresent(Transient.class) || field.isAnnotationPresent(Transient.class)) {
				continue;
			}
			clazzField.add(field);
		} // #for
		return clazzField;
	}

	/**
	 * 获取 id 字段
	 * 
	 * @param clazz
	 * @return
	 */
	public static Field getIdField(Class<?> clazz) {
		Field id = null;

		Field[] fields = clazz.getDeclaredFields();
		for (Field field : fields) {
			if (field.isAnnotationPresent(Id.class)) {
				id = field;
				break;
			}
		} // #for

		if (id == null) {
			id = fields[0];
		}

		return id;
	}// #getIdField

	/**
	 * 获取 id 字段
	 * 
	 * @param clazz
	 * @return
	 */
	public static Field getCreatedField(Class<?> clazz) {
		Field createdField = null;

		Field[] fields = clazz.getDeclaredFields();
		for (Field field : fields) {
			if (field.getName().equals("created")) {
				createdField = field;
				break;
			}
		} // #for

		return createdField;
	}// #getIdField

	public static Object trunMapToObjAll(Map<String, Object> map, Class<?> clazz) {
		Object obj = null;
		if (map == null || map.isEmpty()) {
			return obj;
		}
		try {
			obj = clazz.newInstance();
			List<Field> fields = ClassTools.getClassFields(clazz);
			for (Field field : fields) {
				if (field.isAnnotationPresent(Transient.class)) {
					continue;
				}
				Object val = map.get(field.getName());
				if (val != null) {
					if (field.getType() == BigDecimal.class) {
						ClassTools.setClassVal(field, obj, ChkUtil.getBigDecimal(val.toString()));
					} else if (field.getType() == Timestamp.class) {
						ClassTools.setClassVal(field, obj,
								new Timestamp((long) ChkUtil.getNumber(val.toString(), Long.class)));
					} else {
						ClassTools.setClassVal(field, obj, val);
					}
				}
			}
		} catch (InstantiationException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

		return obj;
	}

	public static <T extends DbModel> T trunMapToObj(Map<String, Object> map, Class<T> clazz) {
		T obj = null;
		if (map == null || map.isEmpty()) {
			return obj;
		}
		try {
			obj = clazz.newInstance();
			obj.map = map;
			List<Field> fields = ClassTools.getClassFields(clazz);
			for (Field field : fields) {
				if (field.isAnnotationPresent(Transient.class)) {
					continue;
				}
				Object val = map.get(field.getName());
				if (val != null && field.getType() == BigDecimal.class) {
					ClassTools.setClassVal(field, obj, ChkUtil.getBigDecimal(val.toString()));
				} else {
					ClassTools.setClassVal(field, obj, val);
				}
			}
		} catch (InstantiationException e) {
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			e.printStackTrace();
		}
		return obj;
	}

	// className 是否包含 字段 field
	public static boolean contain(String className, String fieldName) throws Exception {
		Class<?> clazz = Class.forName(className);
		Field[] fields = clazz.getDeclaredFields();
		for (Field field : fields) {
			if (field.getName().equals(fieldName)) {
				return true;
			}
		} // #for

		return false;
	}

	// 转换 jt 查出的 List<Map> 对象为 List<DbModel>对象
	public static <T extends DbModel> List<T> turnListToObjectList(List<Map<String, Object>> queryForList,
			Class<T> clazz) {
		List<T> list = new ArrayList<>();
		for (Map<String, Object> map : queryForList) {
			T obj = (T) ClassTools.trunMapToObj(map, clazz);
			list.add(obj);
		}
		return list;
	}

	public static <T extends DbModel> Map<String, Object> objToMap(T obj) {
		Map<String, Object> map = new HashMap<String, Object>();
		List<Field> fields = ClassTools.getClassFields(obj.getClass());
		for (Field field : fields) {
			Object val = getClassVal(field, obj);
			map.put(field.getName(), val);
		}

		return map;
	}

	public static Field getField(Class<?> clazz, String fieldName) {
		List<Field> fields = getClassFields(clazz);
		for (Field field : fields) {
			if (field.getName().equals(fieldName)) {
				return field;
			}
		}
		return null;
	}

	// 将 Map 转换成model 打印出来
	public static void mapToModel(Map<String, Object> mapToModel) {
		System.err.println("*************************************************");
		System.err.println("public class Model {");
		mapToModel.forEach((key, val) -> {
			System.err.println("\tprivate " + val.getClass().getSimpleName() + " " + key + ";");
		});

		System.err.println("}");
		System.err.println("*************************************************");
	}

}
